package main

import (
	"learngo/errhandling/fileserver/filelist"
	"log"
	"net/http"
	_ "net/http/pprof" // 虽然没有用到但是要load一些帮助程序进来，加_ 不报错
	"os"
)

type appHandler func(writer http.ResponseWriter,
	request *http.Request) error

// 函数式编程，
func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {
	return func(writer http.ResponseWriter, request *http.Request) {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Panic: %v", r)
				http.Error(writer,
					http.StatusText(http.StatusInternalServerError),
					http.StatusInternalServerError)
			}
		}() // 对异常进行操作，对服务器进行保护
		err := handler(writer, request)
		if err != nil {
			//log.Warn("Error handling request: %s", err.Error())  // 不是标准库
			log.Printf("Error occurred"+"handling request: %s", err.Error())
			// user error
			//对err 进行Type Assertion, 判断是不是UserErr,是的话就可以展示给用户看
			if userErr, ok := err.(userError); ok { // Type Assertion
				http.Error(writer,
					userErr.Message(),
					http.StatusBadRequest)
				return
			}
			// system error
			code := http.StatusOK
			// 文件不同的错误类型
			switch {

			case os.IsNotExist(err): // 找不到资源
				code = http.StatusNotFound
			case os.IsPermission(err):
				code = http.StatusForbidden // 没有权限，错误检测，在linux中文件权限改为500，访问时就没有权限
			default:
				code = http.StatusInternalServerError
			}
			http.Error(
				writer,                // 向谁来汇报err
				http.StatusText(code), // error, 写错误码是为了不暴露内部错误的具体原因
				code)

		}
	}
}

type userError interface {
	// 区分能给用户看的信息及不能给用户看的信息
	// 接口声明可接口的实现者可以在不同文件
	error
	Message() string
}

func main() {
	http.HandleFunc("/", errWrapper(filelist.HandleFileList))
	err := http.ListenAndServe(":9999", nil)
	if err != nil {
		panic(err)
	}
}
